package org.halk.controller;

import org.halk.pojo.entity.StudentTest;
import org.halk.repository.StudentTestRepository;
import org.halk.servie.TestService;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * ## 2、事务相关
 * <p>
 * ### 1、spring事务的传播机制（7种）
 * <p>
 * - propagation.required
 * - spring的默认传播机制，当前上下文中没有事务则创建一个，有则加入
 * - 对于一个代理对象内的方法调用，userService.a()调用b()，如果a方法没有加事务，那么b方法加不加事务注解，都是不生效的；如果a方法加了事务，b方法以a事务为主
 * - 对于不同的代理对象的方法调用效果则不同，userService.a()调用infoService.b(),如果a方法加了事务注解，b方法要以a为主；a没加，b加了事务则独立生效
 * <p>
 * - propagation.supports
 * - 当前上下文中有事务则加入，否则不能创建新的事务
 * - 对于不同的代理对象的方法调用，userService.a()调用infoService.b(),如果a方法加了事务注解，b方法要以a为主；a没加，b加了并设置supports传播机制是不生效的
 * - 对于不同的代理对象的方法调用，userService.a()调用infoService.b(),如果a方法
 * 加了事务注解并设置supports传播机制，因a之前没有事务，则a也没事务，b加了并设置supports传播机制也是无事务的，如果b设置了required，则b会创建一个新的事务
 * <p>
 * - propagation.mandatory
 * - 当前上下文中必须要事务，否则抛异常，后续的事务不受影响
 * <p>
 * - propagation.requires_new
 * - 不管当前上下文中是否有事务，都会创建开启一个新的事务，不受调用者的回滚影响
 * <p>
 * - propagation.not_supports
 * - 不管当前上下文中是否有事务，都会以非事务的方式执行
 * <p>
 * - propagation.never
 * - 总是以非事务方式执行，当前上下文中有事务则抛异常
 * <p>
 * - rpopagation.nested
 * - 当前上下文中有事务，则在嵌套事务中执行，可单独回滚外层事务不受影响，外层事务回滚则嵌套事务也要回滚；上下文中没有事务，则开启一个新的事务
 *
 * @Author halk
 * @Date 2023/9/7 10:54
 */
@RestController
@RequestMapping("/ts")
public class TransactionTestController {

    @Resource
    private StudentTestRepository studentTestRepository;

    @Resource
    private EntityManager entityManager;


    @Resource
    private TestService testService;

    /**
     * 1、同一个代理对象内的互相调用，看起始方法的事务
     * 2、不同代理对象的调用，第一个对象不含事务，不影响调用方法的事务
     *
     * @return
     */

    @GetMapping("/str")
    @Transactional(rollbackFor = {RuntimeException.class})
    public String get() throws Exception {
        test01();

        try {
//            testService.test01();
        } catch (Exception e) {
//            throw new RuntimeException(e);
        }

//        testService.test02();


        StudentTest studentTest = studentTestRepository.findById(2).get();
        studentTest.setName("dfdfdghhhhhh");
        System.out.println(studentTest);

        throw new RuntimeException("dfddd");
//        return "hello";
    }

    @Transactional(rollbackFor = {RuntimeException.class})
    public void test01() throws Exception {
        StudentTest studentTest = studentTestRepository.findById(2).get();
        System.out.println(studentTest);
        studentTest.setAge(444);
        studentTestRepository.save(studentTest);

        throw new Exception("dfddd");
//        int i = 1/0;
    }

    @Transactional
    public void test() {
        List<StudentTest> list2 = studentTestRepository.findAll();
        list2.forEach(System.out::println);

        List<StudentTest> collect = list2.stream().sorted(Comparator.comparing(StudentTest::getName)).map(x -> {
            StudentTest studentTest = new StudentTest();
            BeanUtils.copyProperties(x, studentTest);
            return studentTest;
        }).collect(Collectors.toList());
        for (StudentTest studentTest : collect) {
            studentTest.setName("的发射点发射点");
        }

        List<StudentTest> list3 = studentTestRepository.findAll();
        list3.forEach(System.out::println);
    }
}
